home *** CD-ROM | disk | FTP | other *** search
/ The 640 MEG Shareware Studio 4 / The 640 Meg Shareware Studio CD-ROM Volume IV (Data Express)(1994).ISO / clang / xlib05.zip / XDISCUSS.ZIP / MODEX1.TXT < prev    next >
Text File  |  1993-08-28  |  22KB  |  547 lines

  1. Title:        INTRODUCTION TO MODE X
  2.  
  3. Version:        1.7
  4.  
  5. Author:        Robert Schmidt
  6.  
  7. Copyright:    (C) 1993 of Ztiff Zox Softwear - refer to Status below.
  8.  
  9. Last revision:  28-Aug-93
  10.  
  11. Figures:    1. M13ORG - memory organization in mode 13h
  12.         2. MXORG - memory organization in unchained modes
  13.  
  14.         The figures are available both as 640x480x16 bitmaps
  15.         (in GIF format), and as 7-bit ASCII text (ASC) files.
  16.  
  17. C sources:    1. LIB.C v1.1 - simple graphics library for planar,
  18.                    256-color modes - optionally self-testing.
  19.  
  20.                 Excerpts from the source(s) appear in this article.
  21.                 Whenever there are conflicts, the external source file(s),
  22.         _not_ the excerpts provided here, are correct (or, at
  23.         least, newest).
  24.  
  25. Status:        This article, its associated figures and source listings
  26.         named above, are all donated to the public domain.
  27.         Do with it whatever you like, just don't claim it's your
  28.         work, or make money on it without doing some work
  29.                 yourself.  Please distribute the archive in its entirety.
  30.  
  31.         The standard disclaimer applies.
  32.  
  33. Index:        0. ABSTRACT
  34.         1. INTRODUCTION TO THE VGA AND ITS 256-COLOR MODE
  35.         2. GETTING MORE PAGES AND PUTTING YOUR FIRST PIXEL
  36.         3. THE ROAD FROM HERE
  37.         4. BOOKS ON THE SUBJECT
  38.                 5. BYE - FOR NOW
  39.  
  40.  
  41. 0. ABSTRACT
  42.  
  43. This text gives a fairly basic, yet technical, explanation to what, why
  44. and how Mode X is.  It first tries to explain the layout of the VGA
  45. memory and the shortcomings of the standard 320x200 256-color mode,
  46. then gives instructions on how one can progress from mode 13h to a
  47. multipage, planar 320x200 256-color mode, and from there to the
  48. quasi-standard 320x240 mode, known as Mode X.
  49.  
  50. A little experience in programming the standard VGA mode 13h
  51. (320x200 in 256 colors) is assumed.  Likewise a good understanding of
  52. hexadecimal notation and the concepts of segments and I/O ports is
  53. assumed.  Keep a VGA reference handy, which at least should have
  54. definitions of the VGA registers at bit level.
  55.  
  56. Throughout the article, a simple graphics library for unchained (planar)
  57. 256-color modes is developed.  The library supports the 320x200 and
  58. 320x240 modes, active and visible pages, and writing and reading
  59. individual pixels.
  60.  
  61.  
  62. 1. INTRODUCTION TO THE VGA AND ITS 256-COLOR MODE
  63.  
  64. Since its first appearance on the motherboards of the IBM PS/2 50, 60
  65. and 80 models in 1987, the Video Graphics Array has been the de facto
  66. standard piece of graphics hardware for IBM and compatible personal
  67. computers.  The abbreviation, VGA, was to most people synonymous with
  68. acceptable resolution (640x480 pixels), and a stunning rainbow of colors
  69. (256 from a palette of 262,144), at least compared to the rather gory
  70. CGA and EGA cards.
  71.  
  72. Sadly, to use 256 colors, the VGA BIOS limited the users to 320x200
  73. pixels, i.e. the well-known mode 13h.  This mode has one good and one
  74. bad asset.  The good one is that each pixel is easily addressable in
  75. the video memory segment at 0A000h.  Simply calculate the offset using
  76. this formula:
  77.  
  78. offset = (y * 320) + x;
  79.  
  80. Set the byte at this address (0A000h:offset) to the color you want, and
  81. the pixel is there.  Reading a pixel is just as simple: just read a
  82. byte.  This was heaven, compared to the hell of planes and masking
  83. registers needed in 16-color modes.  Suddenly, the distance from a
  84. graphics algorithm on paper to an implemented graphics routine was cut
  85. down to a fraction.  The results were impressively fast too!
  86.  
  87. The bad asset is that mode 13h is also limited to only one page, i.e.
  88. the VGA can only hold one screenful at any one time.  Most 16-color
  89. modes let the VGA hold more than one page, and this enables you to show
  90. one of the pages to the user, while drawing on another page in the
  91. meantime.  Page flipping is an important concept in making flicker free
  92. animations.  Nice looking and smooth scrolling is also almost impossible
  93. in this mode using plain VGA hardware.
  94.  
  95. Now, the alert reader might say: "Hold on a minute!  If mode 13h enables
  96. only one page, this means that there is memory for only one page.  But I
  97. know for a fact that all VGAs have at least 256 Kb RAM, and one 320x200
  98. 256-color page should consume only 320*200=64000 bytes, which is less
  99. than 64 Kb.  A standard VGA should room a little more than four 320x200
  100. pages!"  Quite correct, and to see how the BIOS puts this limitation on
  101. mode 13h, I'll elaborate a little on the memory organization of the VGA.
  102.  
  103. The memory is separated into four bit planes.  The reason for this stems
  104. from the EGA, where graphics modes were 16-color.  Using bit planes, the
  105. designers chose to let each pixel on screen be addressable by a single
  106. bit in a single byte in the video segment.  Assuming the palette has
  107. not been modified from the default, each plane represent one of the EGA
  108. primary colors: red, green, blue and intensity.  When modifying the bit
  109. representing a pixel, the Write Plane Enable register is set to the
  110. wanted color.  Reading is more complex and slower, since you can
  111. only read from a single plane at a time, by setting the Read Plane
  112. Select register.  Now, since each address in the video segment can
  113. access 8 pixels, and there are 64 Kb addresses, 8 * 65,536 = 524,288
  114. 16-color pixels can be accessed.  In a 320x200 16-color mode, this makes
  115. for about 8 (524,288/(320*200)) pages, in 640x480 you get nearly 2
  116. (524,288/(640*480)) pages.
  117.  
  118. In a 256-color mode, the picture changes subtly.  The designers decided
  119. to fix the number of bit planes to 4, so extending the logic above to 8
  120. planes and 256 colors does not work.  Instead, one of their goals was to
  121. make the 256-color mode as easily accessible as possible.  Comparing the
  122. 8 pixels/address in 16-color modes to the 1-to-1 correspondence of
  123. pixels and addresses of mode 13h, one can say that they have
  124. succeeded, but at a certain cost.  For reasons I am not aware of, the
  125. designers came up with the following effective, but memory-wasting
  126. scheme:
  127.  
  128. The address space of mode 13h is divided evenly across the four bit
  129. planes.  When an 8-bit color value is written to a 16-bit address in the
  130. VGA segment, a bit plane is automatically selected by the 2 least
  131. significant bits of the address.  Then all 8 bits of the data is written
  132. to the byte at the 16-bit address in the selected bitplane (have a look at
  133. figure 1).  Reading works exactly the same way.  Since the bit planes are so
  134. closely tied to the address, only every fourth byte in the video memory is
  135. accessible, and 192 Kb of a 256 Kb VGA go to waste.  Eliminating the
  136. need to bother about planes sure is convenientand beneficial, but in
  137. most people's opinion the loss of 3/4 of VGA memory is too much.
  138.  
  139. To accomodate this new method of accessing video memory, the VGA
  140. designers introduced a new configuration bit called Chain-4, which
  141. resides as bit number 3 in index 4 of the Sequencer.  In 16-color modes,
  142. the default state for this bit is off (zero), and the VGA operates as
  143. described earlier.  In the VGA's standard 256-color mode, mode 13h, this
  144. bit is turned on (set to one), and this turns the tieing of bit
  145. planes and memory address on.
  146.  
  147. In this state, the bit planes are said to be chained together.
  148.  
  149. Note that Chain-4 in itself is not enough to set a 256-color mode -
  150. there are other registers which deals with the other subtle changes in
  151. nature from 16 to 256 colors.  But, as we now will base our work with
  152. mode X on mode 13h, which already is 256-color, we won't bother about
  153. these for now.
  154.  
  155.  
  156. 2. GETTING MORE PAGES AND PUTTING YOUR FIRST PIXEL
  157.  
  158. The observant reader might at this time suggest that clearing the
  159. Chain-4 bit after setting mode 13h will give us access to all 256 Kb of
  160. video memory, as the two least significant bits of the byte address
  161. won't be `wasted' on selecting a bit plane.  This is correct.  You might
  162. also start feeling a little uneasy, because something tells you that
  163. you'll instantly loose the simple addressing of mode 13h.  Sadly, that
  164. is also correct.
  165.  
  166. At the moment Chain-4 is cleared, each byte offset addresses *four*
  167. sequential pixels.  Before writing to a byte offset in the video
  168. segment, you should make sure that the 4-bit mask in the Write Plane
  169. Enable register is set correctly, according to which of the four
  170. addressable pixels you want to modify.  In essence, it works like a
  171. 16-color mode with a twist.  See figure 2.
  172.  
  173. So, is this mode X?  Not quite.  We need to elaborate to the VGA how to
  174. fetch data for refreshing the monitor image.  Explaining the logic
  175. behind this is beyond the scope of this getting-you-started text, and it
  176. wouldn't be very interesting anyway.  Here is the minimum snippet of
  177. code to initiate the 4 page variant of mode 13h, written in plain C,
  178. using some DOS specific features (see header for a note about the
  179. sources included):
  180.  
  181. ----8<-------cut begin------
  182.  
  183. /* width and height should specify the mode dimensions.  widthBytes
  184.    specify the width of a line in addressable bytes. */
  185.  
  186. int width, height, widthBytes;
  187.  
  188. /* actStart specifies the start of the page being accessed by
  189.    drawing operations.  visStart specifies the contents of the Screen
  190.    Start register, i.e. the start of the visible page */
  191.  
  192. unsigned actStart, visStart;
  193.  
  194. /*
  195.  * set320x200x256_X()
  196.  *    sets mode 13h, then turns it into an unchained (planar), 4-page
  197.  *    320x200x256 mode.
  198.  */
  199.  
  200. set320x200x256_X()
  201.     {
  202.  
  203.     union REGS r;
  204.  
  205.     /* Set VGA BIOS mode 13h: */
  206.  
  207.     r.x.ax = 0x0013;
  208.     int86(0x10, &r, &r);
  209.  
  210.     /* Turn off the Chain-4 bit (bit 3 at index 4, port 0x3c4): */
  211.  
  212.     outport(SEQU_ADDR, 0x0604);
  213.  
  214.     /* Turn off word mode, by setting the Mode Control register
  215.        of the CRT Controller (index 0x17, port 0x3d4): */
  216.  
  217.     outport(CRTC_ADDR, 0xE317);
  218.  
  219.     /* Turn off doubleword mode, by setting the Underline Location
  220.        register (index 0x14, port 0x3d4): */
  221.  
  222.     outport(CRTC_ADDR, 0x0014);
  223.  
  224.     /* Clear entire video memory, by selecting all four planes, then
  225.        writing 0 to the entire segment. */
  226.  
  227.     outport(SEQU_ADDR, 0x0F02);
  228.     memset(vga+1, 0, 0xffff); /* stupid size_t exactly 1 too small */
  229.     vga[0] = 0;
  230.  
  231.     /* Update the global variables to reflect dimensions of this
  232.        mode.  This is needed by most future drawing operations. */
  233.  
  234.         width   = 320;
  235.     height    = 200;
  236.  
  237.         /* Each byte addresses four pixels, so the width of a scan line
  238.            in *bytes* is one fourth of the number of pixels on a line. */
  239.  
  240.         widthBytes = width / 4;
  241.  
  242.         /* By default we want screen refreshing and drawing operations
  243.            to be based at offset 0 in the video segment. */
  244.  
  245.     actStart = visStart = 0;
  246.  
  247.     }
  248.  
  249. ----8<-------cut end------
  250.  
  251. As you can see, I've already provided some of the mechanics needed to
  252. support multiple pages, by providing the actStart and visStart variables.
  253. Selecting pages can be done in one of two contexts:
  254.  
  255.     1) selecting the visible page, i.e. which page is visible on
  256.        screen, and
  257.  
  258.     2) selecting the active page, i.e. which page is accessed by
  259.        drawing operations
  260.  
  261. Selecting the active page is just a matter of offsetting our graphics
  262. operations by the address of the start of the page, as demonstrated in
  263. the put pixel routine below.  Selecting the visual page must be passed
  264. in to the VGA, by setting the Screen Start register.  Sadly enough, the
  265. resolution of this register is limited to one addressable byte, which
  266. means four pixels in unchained 256-color modes.  Some trickery is needed
  267. for 1-pixel smooth, horizontal scrolling, but I'll make that a subject
  268. for later.  The setXXXStart() functions provided here accept byte
  269. offsets as parameters, so they'll work in any mode.  If widthBytes and
  270. height are set correctly, so will the setXXXPage() functions.
  271.  
  272. ----8<-------cut begin------
  273.  
  274. /*
  275.  * setActiveStart() tells our graphics operations which address in video
  276.  * memory should be considered the top left corner.
  277.  */
  278.  
  279. setActiveStart(unsigned offset)
  280.     {
  281.     actStart = offset;
  282.     }
  283.  
  284. /*
  285.  * setVisibleStart() tells the VGA from which byte to fetch the first
  286.  * pixel when starting refresh at the top of the screen.  This version
  287.  * won't look very well in time critical situations (games for
  288.  * instance) as the register outputs are not synchronized with the
  289.  * screen refresh.  This refresh might start when the high byte is
  290.  * set, but before the low byte is set, which produces a bad flicker.
  291.  */
  292.  
  293. setVisibleStart(unsigned offset)
  294.     {
  295.     visStart = offset;
  296.     outport(CRTC_ADDR, 0x0C);        /* set high byte */
  297.     outport(CRTC_ADDR+1, visStart >> 8);
  298.     outport(CRTC_ADDR, 0x0D);        /* set low byte */
  299.     outport(CRTC_ADDR+1, visStart & 0xff);
  300.     }
  301.  
  302. /*
  303.  * setXXXPage() sets the specified page by multiplying the page number
  304.  * with the size of one page at the current resolution, then handing the
  305.  * resulting offset value over to the corresponding setXXXStart()
  306.  * function.  The first page number is 0.
  307.  */
  308.  
  309. setActivePage(int page)
  310.     {
  311.     setActiveStart(page * widthBytes * height);
  312.     }
  313.  
  314. setVisiblePage(int page)
  315.     {
  316.     setVisibleStart(page * widthBytes * height);
  317.     }
  318.  
  319. ----8<-------cut end------
  320.  
  321. Due to the use of bit planes, the graphics routines tend to get more
  322. complex than in mode 13h, and your first versions will generally tend to
  323. be a little slower than mode 13h algorithms.  Here's a put pixel routine
  324. for any unchained 256-color mode (it assumes that the 'width' variable
  325. from the above code is set correctly).  Optimizing is left as an exercise
  326. to you, the reader.  This will be the only drawing operation I'll cover
  327. in this article.
  328.  
  329. ----8<-------cut begin------
  330.  
  331. putPixel_X(int x, int y, char color)
  332.     {
  333.  
  334.     /* Each address accesses four neighboring pixels, so set
  335.        Write Plane Enable according to which pixel we want
  336.        to modify.  The plane is determined by the two least
  337.        significant bits of the x-coordinate: */
  338.  
  339.     outportb(0x3c4, 0x02);
  340.     outportb(0x3c5, 0x01 << (x & 3));
  341.  
  342.     /* The offset of the pixel into the video segment is
  343.        offset = (width * y + x) / 4, and write the given
  344.        color to the plane we selected above.  Heed the active
  345.        page start selection. */
  346.  
  347.     vga[(unsigned)(widthBytes * y) + (x / 4) + actStart] = color;
  348.  
  349.     }
  350.  
  351. char getPixel_X(int x, int y)
  352.     {
  353.  
  354.     /* Select the plane from which we must read the pixel color: */
  355.  
  356.     outport(GRAC_ADDR, 0x04);
  357.     outport(GRAC_ADDR+1, x & 3);
  358.  
  359.     return vga[(unsigned)(widthBytes * y) + (x / 4) + actStart];
  360.  
  361.     }
  362.  
  363. ----8<-------cut end------
  364.  
  365.  
  366. However, by now you should be aware of that the Write Plane Enable
  367. register isn't limited to selecting just one bit plane, like the
  368. ReadPlane Select register is.  You can enable any combination of all
  369. four to be written.  This ability to access 4 pixels with one
  370. instruction helps quadrupling the speed, especially when drawing
  371. horizontal lines and filling polygons of a constant color.  Also, most
  372. block algorithms can be optimized in various ways so that they need only
  373. a constant number of OUTs (typically four) to the Write Plane Enable
  374. register.  OUT is a relatively slow instruction.
  375.  
  376. The gained ability to access the full 256 Kb of memory on a standard
  377. VGA enables you to do paging and all the goodies following from that:
  378. smooth scrolling over large maps, page flipping for flicker free
  379. animation... and I'll leave something for your own imagination.
  380.  
  381. In short, the stuff gained from using mode X more than upweighs the
  382. additional complexity of using a planar mode.
  383.  
  384. Now, the resolution of the mode is of little interest in this
  385. context.  Nearly any 256-color resolution from (about) 80x8 to 400x300
  386. is available for most VGAs.  I'll dwell particularly by 320x240, as this
  387. is the mode that Michael Abrash introduced as 'Mode X' in his DDJ
  388. articles.  It is also the resolution that most people refer to when
  389. using that phrase.
  390.  
  391. The good thing about the 320x240 mode is that the aspect ratio is
  392. 1:1, which means that each pixels is 'perfectly' square, i.e. not
  393. rectangular like in 320x200.  An ellipse drawn with the same number of
  394. pixels along both main axes will look like a perfect circle in 320x240,
  395. but like a subtly tall ellipse in 320x200.
  396.  
  397. Here's a function which sets the 320x240 mode.  You'll notice that
  398. it depends on the first piece of code above:
  399.  
  400. ----8<-------cut begin------
  401.  
  402. set320x240x256_X()
  403.     {
  404.  
  405.     /* Set the unchained version of mode 13h: */
  406.  
  407.     set320x200x256_X();
  408.  
  409.     /* Modify the vertical sync polarity bits in the Misc. Output
  410.        Register to achieve square aspect ratio: */
  411.  
  412.     outportb(0x3C2, 0xE7);
  413.  
  414.     /* Modify the vertical timing registers to reflect the increased
  415.        vertical resolution, and to center the image as good as
  416.        possible: */
  417.  
  418.     outport(0x3D4, 0x2C11);        /* turn off write protect */
  419.     outport(0x3D4, 0x0D06);        /* vertical total */
  420.     outport(0x3D4, 0x3E07);        /* overflow register */
  421.     outport(0x3D4, 0xEA10);        /* vertical retrace start */
  422.     outport(0x3D4, 0xAC11);        /* vertical retrace end AND wr.prot */
  423.     outport(0x3D4, 0xDF12);        /* vertical display enable end */
  424.     outport(0x3D4, 0xE715);        /* start vertical blanking */
  425.     outport(0x3D4, 0x0616);        /* end vertical blanking */
  426.  
  427.     /* Update mode info, so future operations are aware of the
  428.        resolution: */
  429.  
  430.     height = 240;
  431.  
  432.     }
  433.  
  434. ----8<-------cut end------
  435.  
  436. As you've figured out, this mode will be completely compatible with the
  437. utility functions presented earlier, thanks to the global variable
  438. 'height'.
  439.  
  440. Other resolutions are achieved through giving other values to the sync
  441. timing registers of the VGA, but this is quite a large and complex
  442. subject, so I'll postpone this to later, if ever.
  443.  
  444. Anyway, I hope I've helped getting you started using mode X.  As far as
  445. I know, the two modes I've used above should work on *any* VGA and Super
  446. VGA available, so this is pretty stable stuff.  Good luck!
  447.  
  448.  
  449. 3. THE ROAD FROM HERE
  450.  
  451. I'm providing information on various libraries and archives which relate
  452. to what this article deals with.  If you want me to add anything to this
  453. list (for future articles), let me know, although I can't promise anything.  
  454. I am assuming you have ftp access.
  455.  
  456. netcom.com:/pub/profile/game-dev/msdos/xlib04c.zip
  457.  
  458. This is the current de facto C/assembler library for programming
  459. unchained modes (do not confuse with a X Windows library).  All sources
  460. are included, and the library is totally free.  It has functions for
  461. pixels, lines, circles, bezier curves, mouse handling, sprites (bitmaps),
  462. compiled bitmaps, and supports a number of resolutions.
  463.  
  464. graphprg.zip
  465.  
  466. Michael Abrash' articles in Doctor Dobbs Journal is always mentioned
  467. with awe.  In this 350 Kb archive, most of his interesting stuff has
  468. been gathered.  Read about Mode X development and techniques from month
  469. to month.  Included is also all the individual source code snippets from
  470. each article, and also the full XSHARP library providing linedrawing,
  471. polygons, bitmaps, solid 3D projection and speedy rendering, and even an
  472. implementation of 2D texture mapping (can be used for quasi-3D texture
  473. mapping), plus an article on assembly optimization on the i86 processor
  474. family.  Definitely recommended.
  475.  
  476. oak.oakland.edu:/pub/msdos/vga/vgadoc2.zip
  477.  
  478. This is a bare bones VGA register reference.  It also contains register
  479. references for the CGA, EGA and Hercules cards, in addition to dozens of
  480. SuperVGAs.  Check out the BOOKS section for some decent VGA references
  481. though - you don't want to start tweaking without a real one.
  482.  
  483. oak.oakland.edu:/pub/msdos/vga/tweak10.zip
  484.  
  485. might be of interest to the more adventurous reader.  TWEAK lets you
  486. play around with the registers of the VGA in an interactive manner.
  487. Various testing screens for viewing your newmade modes are applied at
  488. the press of a key.  Keep a VGA reference handy.  Don't try it if this
  489. is the first time you've heard of 'registers' or 'mode X' or 'tweaking'.
  490. Watch out for a new version of TWEAK using the familiar Turbo Vision
  491. interface, due before Christmas 1993!
  492.  
  493.  
  494. 4. BOOKS ON THE SUBJECT
  495.  
  496. Extremely little has been published in written form about using
  497. 'Mode X'-style modes.  Below are some books which cover VGA programming
  498. at varying degrees of technical level, but the only one to mention
  499. unchained modes and Mode X, is Michael Abrash'.  I'd get one of the VGA
  500. references first, though.
  501.  
  502.   o  George Sutty & Steve Blair : "Advanced Pogrammer's Guide to the
  503.      EGA/VGA" from Brady.  A bit old perhaps, but covers all *standard*
  504.      EGA/VGA registers, and discusses most BIOS functions and other
  505.      operations.  Contains disk with C/Pascal/assembler source code.
  506.      There's a sequel out for SuperVGAs, which I haven't seen.
  507.  
  508.   o  Michael Abrash : "Power Graphics Programming" from QUE/Programmer's
  509.      Journal.  Collections of (old) articles from Programmer's Journal on
  510.      EGA/VGA, read modes and write modes, animation, tweaking (320x400
  511.      and 360x480).  His newer ravings in DDJ covers fast 256-color
  512.      bitmaps, compiled bitmaps, polygons, 3D graphics, texture mapping
  513.      among other stuff.
  514.  
  515.   o  Richard F. Ferraro : "Programmer's Guide to the EGA and VGA video
  516.      cards including Super VGA".  I don't have this one, but heard it's
  517.      nice.  Detailed coverage of all EGA/VGA registers.  The Super VGA
  518.      reference makes it attractive.
  519.  
  520.   o  Richard Wilton : "Programmer's Guide to PC & PS/2 Video Systems"
  521.      Less technical, more application/algorithm oriented.  Nice enough,
  522.      even though it is a bit outdated, in that he discusses CGA and
  523.      Hercules cards just as much as EGA/VGA.
  524.  
  525.  
  526. 5. BYE - FOR NOW
  527.  
  528. I am considering writing a text describing in more detail the process of
  529. using TWEAK to achieve the VGA resolution you want or need.  However, I
  530. thought I'd let this document go first, and see if I get any reactions.
  531. If I don't, I'll stop.  Feel free to forward any suggestions,
  532. criticisms, bombs and beers.
  533.  
  534. I can be reached via:
  535.  
  536.   o  e-mail: robert@alkymi.unit.no
  537.  
  538.   o  land mail:
  539.  
  540.      Robert Schmidt
  541.      Ole Nordgaardsvei 44
  542.      N-7049 Trondheim
  543.      NORWAY
  544.  
  545. Nothing would encourage or please me more than a postcard from where you
  546. live!
  547.